package com.example.csvphonetoregion;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
 * 应用启动后自动执行：读取csv文件到redis
 */
@Slf4j
@Component
public class ReadCsvToRedisStart implements CommandLineRunner {

    // 文件位置
    private final static String REGION_CSV_PATH = "classpath:/static/region/phonetmp.csv";

    // 存放到redis中的key
    private final static String PHONE_REGION_KEY = "country_phone_region_info";

    // 注入资源加载接口
    @Autowired
    private ResourceLoader resourceLoader;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Override
    public void run(String... args) throws Exception {
        // 首先先拿到redis中key的数目
        HashOperations<String, Object, Object> redisMap = redisTemplate.opsForHash();
        long size = redisMap.size(PHONE_REGION_KEY);
        if (size > 0) {
            log.info("Redis key {} already has {} entries, skip loading.", PHONE_REGION_KEY, size);
            return;
        }

        Resource resource = resourceLoader.getResource(REGION_CSV_PATH);
        if (!resource.exists()) {
            log.warn("Region CSV resource not found：{}", REGION_CSV_PATH);
            return;
        }

        // 否则初始化
        try (InputStream inputStream = resource.getInputStream();
             // new InputStreamReader(ism) 使用的是 JVM 默认编码（可能不是 UTF-8），显式指定 StandardCharsets.UTF_8，否则中文或特殊字符会乱码。
             BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {

            String line;
            Map<String, Object> maxLineMap = new HashMap<>();
            final int MAXDATA_TOREDIS = 2000;

            while ((line = reader.readLine()) != null) {
                // 检查字符串变量line是否为空或只包含空白字符，如果是，则跳过当前循环
                if (!StringUtils.hasText(line))
                    continue;

                String[] parts = line.split(",");
                if (parts.length < 4) {
                    log.warn("Invalid CSV line (skip)：{}", line);
                    continue;
                }
                RegionVO regionVO = new RegionVO();
                regionVO.setPhonePrefix(parts[0])
                        .setProvince(parts[1])
                        .setCity(parts[2])
                        .setCarrier(parts[3]);

                // 存入redis
                // 每行调用 redisTemplate.opsForHash().put() 会产生很多网络往返（RTT）。建议收集到 Map，然后 putAll()
                // redisTemplate.opsForHash().put(PHONE_REGION_KEY, parts[0], regionVO);
                maxLineMap.put(parts[0], regionVO);

                // 当 map 达到一定大小时 flush 到 Redis
                if (maxLineMap.size() >= MAXDATA_TOREDIS) {
                    redisTemplate.opsForHash().putAll(PHONE_REGION_KEY, maxLineMap);
                    maxLineMap.clear();
                }
            }

            // 剩余一点不到2000的
            if (!maxLineMap.isEmpty()) {
                redisTemplate.opsForHash().putAll(PHONE_REGION_KEY, maxLineMap);
            }

            log.info("Loaded phone region info into Redis key '{}' successfully.", PHONE_REGION_KEY);
        } catch (IOException e) {
            log.error("Failed to read CSV resource: {}", REGION_CSV_PATH, e);
            throw new RuntimeException("获取手机号信息报错", e);
        } catch (Exception e) {
            log.error("Unexpected error when loading phone region info", e);
            throw new RuntimeException("获取手机号信息报错", e);
        }
    }
}
